<template>
  <el-form
    :model="submitForm"
    :rules="rules"
    :label-width="125"
    ref="submitFormRef"
  >
    <el-row>
      <template v-for="(item, key) in props.formFiledList" :key="key">
        <template v-if="item.showInForm">
          <template v-if="item.jsonFiled">
            <template v-for="(childItem, index) in item.jsonFiled" :key="index">
              <template v-if="childItem.showInForm">
                <el-col :span="item.span">
                  <el-form-item
                    :label="childItem.label + ':'"
                    label-suffix="："
                    :prop="item.filedName + '.' + childItem.filedName"
                  >
                    <component
                      :is="formItemList[childItem.formType]"
                      v-model="submitForm[item.filedName][childItem.filedName]"
                      v-bind="getCtrlMeta(childItem)"
                    ></component>
                  </el-form-item>
                </el-col>
              </template>
            </template>
          </template>
          <template v-else-if="item.children">
            <el-form-item
              :label="item.label + ': '"
              style="width: 100%"
              label-width="125px"
            >
              <sub-table
                :sub-table-list="subTableList"
                :sub-table-data="submitForm[item.filedName]"
                @delete-row-sub="deleteRowSub"
              ></sub-table>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="addOneSubTableData"
                >新增
              </el-button>
            </el-form-item>
          </template>
          <template v-else>
            <template v-if="item.showInForm">
              <el-col :span="item.span">
                <el-form-item :label="item.label + ': '" :prop="item.filedName">
                  <component
                    :is="formItemList[item.formType]"
                    v-model="submitForm[item.filedName]"
                    v-bind="getCtrlMeta(item)"
                    @change="changeEvent"
                    @focus="selectFocusEvent"
                  ></component>
                </el-form-item>
              </el-col>
            </template>
          </template>
        </template>
      </template>
    </el-row>
  </el-form>
</template>

<script lang="ts" setup>
import { ref, unref, watch } from "vue";
import { formItemList } from "@/components/form/formItem/MapElFormItem";
import { BaseFormItem } from "@/components/form/formItem/FormItemMeta";
import { RuleEnum } from "@/components/form/basic/FormEnum";
import SubTable from "@/components/table/subTable/SubTable.vue";

export interface Rule {
  ruleName: RuleEnum; // 校验规则名.
  ruleValue:
    | string
    | number
    | boolean
    | ((
        rule: unknown,
        value: unknown,
        callback: (data?: string) => void
      ) => void); // 校验规则的值.
  message: string; // 校验提示文字.
}

export interface FormFiled {
  filedName: string; // 表格中该字段的字段名.
  label: string; // 表格中该字段展示的名字.
  span: number;
  formType: string;
  required?: boolean; // 该字段是否需要校验
  width?: number; // 表格中该字段所占的宽度.
  minWidth?: number; // 表格中该字段所占的最小宽度.
  showInForm?: boolean; // 该字段是否需要在表单中渲染显示.
  rules: Array<Rule>; // 校验规则
  jsonFiled?: Array<FormFiled>; // json表单字段
  children?: Array<FormFiled>; // 子表
  meta?: BaseFormItem; // 下拉列表的属性
}

export interface baseFormProps {
  modelValue: string | number | Record<string, unknown>;
  formFiledList: Array<FormFiled>;
  submitFormTitle?: string;
}

const props = withDefaults(defineProps<baseFormProps>(), {
  modelValue: "",
  submitFormTitle: "",
  formFiledList: () => {
    return [];
  },
});

const emits = defineEmits<{
  (e: "success-validate"): void;
  (e: "filed-validate"): void;
  (e: "change-event", val: string | unknown): void;
  (e: "select-focus-event"): void;
}>();

// 获取下拉框数据
const selectFocusEvent = () => {
  emits("select-focus-event");
};
// 当下拉选择框数据变化时向外抛出事件
const changeEvent = (val: string | unknown) => {
  emits("change-event", val);
};
// 下拉列表的属性
const getCtrlMeta = (item: FormFiled) => {
  // 新增/编辑弹窗字段是否可以编辑
  if (item.meta) {
    if (item.meta.editDisabled || item.meta.addDisabled) {
      item.meta.disabled = !!(
        (item.meta.editDisabled && props.submitFormTitle == "编辑") ||
        (item.meta.addDisabled && props.submitFormTitle == "新增")
      );
    }
  }
  return item.meta || {};
};

// 添加表单字段的校验规则
const rulesFunction = (formFiledList: Array<FormFiled>) => {
  let temp = {};
  // 遍历表单字段属性，是否需要添加校验规则
  formFiledList.forEach((item) => {
    if (item.jsonFiled !== undefined) {
      // 如果有子字段，递归判断子字段是否需要添加校验规则
      temp[item.filedName] = rulesFunction(item.jsonFiled);
    } else if (item.rules) {
      temp[item.filedName] = [];
      let myTrigger = "blur";
      if (item.formType == "el-form-select-dropdown") {
        myTrigger = "change";
      }
      // 如果该字段需要校验，遍历校验规则并添加
      item.rules.forEach((rule) => {
        temp[item.filedName].push({
          [rule.ruleName]: rule.ruleValue,
          message: rule.message,
          trigger: myTrigger,
        });
      });
    }
  });
  return temp;
};

// 给表单字段添加校验规则
let rules = rulesFunction(props.formFiledList);
console.log(rules);
// 申明表单
const submitFormRef = ref();

// const resetForm = () => {
//   submitFormRef.value.resetFields();
// };

// 表单数据
const submitForm = ref();

// 子表的表结构
const subTableList = ref([] as Array<FormFiled>);
// 子表的字段名称
const subTableName = ref();

// 新建子表时初始化格式
const initSubFormEvent = (subTableList: Array<FormFiled>) => {
  let temp = {};
  subTableList.forEach((filed) => {
    // 如果存在子属性, 则进行递归, 反之则设为空值.
    const objValue = filed.jsonFiled ? initSubFormEvent(filed.jsonFiled) : null;
    temp = Object.assign(temp, { [filed.filedName]: objValue });
  });
  return temp;
};

// 遍历formFiledList，如果有子表，给子表表结构赋值,主表表结构赋值，标记子表名称用于删除操作
const subTableFunction = () => {
  props.formFiledList.forEach((filed) => {
    if (filed.children) {
      subTableList.value = filed.children;
      subTableName.value = filed.filedName;
    }
  });
};
subTableFunction();

// 删除子表中的某条数据
const deleteRowSub = (index: number) => {
  submitForm.value[subTableName.value].splice(index, 1);
};
// 向子表单中添加一条空数据
const addOneSubTableData = () => {
  let initSubForm = initSubFormEvent(subTableList.value); // 初始化新增数据的格式
  submitForm.value[subTableName.value].push(initSubForm);
};

if (typeof props.modelValue !== "undefined") {
  for (const key in submitForm) {
    if (typeof unref(props.modelValue)[key] !== "undefined") {
      submitForm[key] = unref(props.modelValue)[key];
    }
  }
}

const clearValid = () => {
  if (undefined !== submitFormRef.value) {
    submitFormRef.value.clearValidate();
    // submitFormRef.value.resetFields();
  }
};

const validForm = async () => {
  if (undefined !== submitFormRef.value) {
    submitFormRef.value
      .validate()
      .then(() => {
        emits("success-validate");
      })
      .catch(() => {
        console.log("校验失败");
      });
  }
};
watch(
  () => props.modelValue,
  () => {
    submitForm.value = props.modelValue;
    setTimeout(() => {
      clearValid();
    }, 100);
  },
  { immediate: true }
);

defineExpose({ validForm });
</script>

<style scoped></style>
